﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using NUnit.Mocks;
using Rhino.Mocks;
using Rhino.Mocks.Constraints;
using Rhino.Mocks.Impl;
using Rhino.Mocks.Interfaces;
using RoboZip;

namespace RoboZip.Test
{
    [TestFixture]
    class ArgumentParserTest
    {
        private ArgumentParser ap = null;
        private Job job = null;
        private String[] arguments = new String[0];
        private String sourceValid = @"C:\tmp";
        private String sourceInValid = @"C:<\tmp";
        private String destinationValid = @"D:\tmp";
        private String destinationInValid = @"D:|tmp";
        private String fileNameValid = "test.txt";

        [SetUp]
        public void Setup()
        {
            ap = new ArgumentParser();
            job = new Job();
        }

        [TearDown]
        public void TearDown()
        {
            ap = null;
            job = null;
        }
    
        [Test]
        public void ParseArguments_NoArgumentPassed_ReturnsErrorNoArgument()
        {
            arguments = new String[] {};
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.NoArguments));
        }

        [Test]
        public void ParseArguments_AskHelp_WritesHelpToConsole()
        {
            arguments = new String[] { @"/?" };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OnlyOneArgument));
        }

        [Test]
        public void ParseArguments_OnlyOnArgumentPassed_ReturnsErrorOnlyOneArgument()
        {
            arguments = new String[]{ @"Argument" };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OnlyOneArgument));
        }

        [Test]
        public void ParseArguments_SourceArgumentInvalid_ReturnsErrorSource()
        {
            arguments = new String[] { sourceInValid, destinationValid, fileNameValid };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.Source));
        }

        [Test]
        public void ParseArguments_DestinationArgumentInvalid_ReturnsErrorDestination()
        {
            arguments = new String[] { sourceValid, destinationInValid, fileNameValid };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.Destination));
        }

        [Test]
        public void ParseArguments_ValidSourceAndDestination_ReturnsNoError()
        {
            arguments = new String[] { sourceValid, destinationValid, fileNameValid };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.NoError));
        }

        [Test]
        public void ParseArguments_ValidSourceAndDestination_ReturnsJobSource()
        {
            arguments = new String[] { sourceValid, destinationValid, fileNameValid };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.SourcePath, NUnit.Framework.Is.EqualTo(sourceValid));
        }

        [Test]
        public void ParseArguments_ValidSourceAndDestination_ReturnsJobDestination()
        {
            arguments = new String[] { sourceValid, destinationValid };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.DestinationPath, NUnit.Framework.Is.EqualTo(destinationValid));
        }

        [Test]
        public void ParseArguments_OnlyValidSourceAndDestination_ReturnsOneItemInFileList()
        {
            arguments = new String[] { sourceValid, destinationValid };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.FileList.Count, NUnit.Framework.Is.EqualTo(1));
        }

        [Test]
        public void ParseArguments_OnlyValidSourceAndDestination_ReturnsAsterixFiles()
        {
            arguments = new String[] { sourceValid, destinationValid };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.FileList[0].ToString(), NUnit.Framework.Is.EqualTo("*.*"));
        }

        [Test]
        public void ParseArguments_DestinationEqualsSource_ReturnsErrorDestination()
        {
            arguments = new String[] { sourceValid, sourceValid };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.Destination));
        }

        [Test]
        public void ParseArguments_DestinationWithinSource_ReturnsErrorDestination()
        {
            arguments = new String[] { sourceValid, sourceValid + @"\Destination" };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.Destination));
        }

        [Test]
        public void ParseArguments_DestinationNotWithinSource_ReturnsNoError()
        {
            arguments = new String[] { sourceValid, sourceValid + @"Destination" };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.NoError));
        }

        [Test]
        public void ParseArguments_AddValidFile_ReturnsThatFile()
        {
            String file = @"File.txt";
            arguments = new String[] { sourceValid, destinationValid, file };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.FileList[0].ToString(), NUnit.Framework.Is.EqualTo(file));
        }

        [Test]
        public void ParseArguments_AddMultipleFile_ReturnsThoseFiles()
        {
            String[] somefiles = new String[] { @"File_1.txt", @"File_2.*.*", @"File_3.df?" };
            arguments = new String[] { sourceValid, destinationValid, somefiles[0], somefiles[1], somefiles[2] };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.FileList, NUnit.Framework.Is.EqualTo(somefiles));
        }

        [Test]
        public void ParseArguments_OptionValidWithinFiles_ReturnsErrorFileName()
        {   
            String[] somefiles = new String[] { @"File_1.txt", @"File_2.txt", @"/MP:n", @"File_?.df?" };
            arguments = new String[] { sourceValid, destinationValid, somefiles[0], somefiles[1], somefiles[2], somefiles[3] };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.FileName));
        }

        [Test]
        public void ParseArguments_OptionUnknown_ReturnsErrorUnknownOption()
        {
            String option = "/Opt_123";
            String[] somefiles = new String[] { @"File_1.txt", @"File_2.txt" };
            arguments = new String[] { sourceValid, destinationValid, somefiles[0], somefiles[1], option };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionUnknown));
        }
        
        [Test]
        public void ParseArguments_OptionMonitoringPeriodIsMissingParameter_ReturnsErrorOptionMissingParameter()
        {
            String optionMP = "/MP";
            String[] somefiles = new String[] { @"File_1.txt", @"File_2.txt" };
            arguments = new String[] { sourceValid, destinationValid, somefiles[0], somefiles[1], optionMP };
            ap.ParseArguments(ref job, arguments);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionParameterMissing));
        }





        [Test]
        public void CheckOptionMonitoringPeriod_OptionAlreadyPassed_ReturnsErrorOptionPassedTwice()
        {
            job.MonitoringPeriod = MonitoringPeriod.a;
            String[] split = {"/MP" , "n"};
            ArgumentParser.CheckOptionMonitoringPeriod(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionPassedTwice));
        }

        [Test]
        public void CheckOptionMonitoringPeriod_MissingParameter_ReturnsErrorOptionMissingParameter()
        {
            String[] split = { "/MP" };
            ArgumentParser.CheckOptionMonitoringPeriod(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionParameterMissing));
        }

        [Test]
        public void CheckOptionMonitoringPeriod_InvalidParameter_ReturnsErrorOptionParameterUnknown()
        {
            String[] split = { "/MP" , "qwerty" };
            ArgumentParser.CheckOptionMonitoringPeriod(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionParameterUnknown));
        }

        [Test]
        public void CheckOptionMonitoringPeriod_ValidParameter_ReturnsNoError()
        {
            String[] split = { "/MP", "d" };
            ArgumentParser.CheckOptionMonitoringPeriod(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.NoError));
        }

        [Test]
        public void CheckOptionSTART_OptionAlreadyPassed_ReturnsErrorOptionPassedTwice()
        {
            job.Start = new DateTime(2011,11,1,0,0,0);
            String[] split = { "/START", "2011-07-25 02:30:30" };
            ArgumentParser.CheckOptionSTART(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionPassedTwice));
        }

        [Test]
        public void CheckOptionSTART_MissingParameter_ReturnsErrorOptionMissingParameter()
        {
            String[] split = { "/START" };
            ArgumentParser.CheckOptionSTART(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionParameterMissing));
        }

        [Test]
        public void CheckOptionSTART_InvalidParameter_ReturnsErrorOptionParameterUnknown()
        {
            String[] split = { "/START", "2011-0ß7-25 02:30:30" };
            ArgumentParser.CheckOptionSTART(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionParameterUnknown));
        }

        [Test]
        public void CheckOptionSTART_ValidParameter_ReturnsNoError()
        {
            String[] split = { "/START", "2011-07-25 02:30:30" };
            ArgumentParser.CheckOptionSTART(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.NoError));
        }

        [Test]
        public void CheckOptionFNP_OptionAlreadyPassed_ReturnsErrorOptionPassedTwice()
        {
            job.FileNamePattern = "'yyyy'";
            String[] split = { "/FNP", "'mm'" };
            ArgumentParser.CheckOptionFNP(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionPassedTwice));
        }

        [Test]
        public void CheckOptionFNP_MissingParameter_ReturnsErrorOptionMissingParameter()
        {
            String[] split = { "/FNP" };
            ArgumentParser.CheckOptionFNP(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionParameterMissing));
        }

        [Test]
        public void CheckOptionFNP_InvalidParameter_ReturnsErrorFilename()
        {
            String[] split = { "/FNP", " year 'yyyy' ?" };
            ArgumentParser.CheckOptionFNP(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.FileName));
        }

        [Test]
        public void CheckOptionFNP_ValidParameter_ReturnsNoError()
        {
            String[] split = { "/FNP", " year 'yyyy' month 'mm' and other..." };
            ArgumentParser.CheckOptionFNP(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.NoError));
        }

        [Test]
        public void CheckOptionUD_OptionAlreadyPassed_ReturnsErrorOptionPassedTwice()
        {
            job.UpdateDestination = true;
            String[] split = { "/UD" };
            ArgumentParser.CheckOptionUD(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionPassedTwice));
        }

        [Test]
        public void CheckOptionUD_InvalidParameter_ReturnsErrorOptionParameterUnknown()
        {
            String[] split = { "/UD" , "true" };
            ArgumentParser.CheckOptionUD(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionParameterUnknown));
        }

        [Test]
        public void CheckOptionUD_ValidParameter_ReturnsNoError()
        {
            String[] split = { "/UD" };
            ArgumentParser.CheckOptionUD(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.NoError));
        }

        [Test]
        public void CheckOptionDS_OptionAlreadyPassed_ReturnsErrorOptionPassedTwice()
        {
            job.UpdateDestination = true;
            String[] split = { "/DS" };
            ArgumentParser.CheckOptionUD(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionPassedTwice));
        }

        [Test]
        public void CheckOptionDS_InvalidParameter_ReturnsErrorOptionParameterUnknown()
        {
            String[] split = { "/DS", "true" };
            ArgumentParser.CheckOptionUD(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.OptionParameterUnknown));
        }

        [Test]
        public void CheckOptionDS_ValidParameter_ReturnsNoError()
        {
            String[] split = { "/DS" };
            ArgumentParser.CheckOptionUD(ref job, split);
            Assert.That(job.ErrorNumber, NUnit.Framework.Is.EqualTo(ErrorNumber.NoError));
        }

        [Test]
        public void RemoveDublicateWhitespace_StringWithoutWhiteSpace_ReturnsSameString()
        {
            String s = "StringWithoutWhiteSpace";
            Assert.That(ArgumentParser.RemoveDublicateWhitespace(s), NUnit.Framework.Is.EqualTo(s));
        }
        
        [Test]
        public void RemoveDublicateWhitespace_StringWithSingleWhiteSpaces_ReturnsSameString()
        {
            String s = "String With Single WhiteSpaces";
            Assert.That(ArgumentParser.RemoveDublicateWhitespace(s), NUnit.Framework.Is.EqualTo(s));
        }

        [Test]
        public void RemoveDublicateWhitespace_StringWithMultipleWhiteSpaces_ReturnsStringWithSingleWhiteSpaces()
        {
            String s1 = "String  With   White    Spaces";
            String s2 = "String With White Spaces";
            Assert.That(ArgumentParser.RemoveDublicateWhitespace(s1), NUnit.Framework.Is.EqualTo(s2));
        }
    }
}
